package com.heima.gateway.filter;

import com.heima.gateway.util.AppJwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

@Component
@Slf4j
public class LoginFilter implements GlobalFilter, Ordered {
    /*
    方法定义与作用：
    filter(ServerWebExchange exchange, GatewayFilterChain chain)
    是Spring Cloud Gateway中一个核心的过滤器方法，
    用于在请求到达目标服务之前或之后执行一些操作，
    如日志记录、安全验证、请求/响应修改等。
    它是一个异步方法，返回Mono<Void>类型，表示处理完成后无数据返回。
     */

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        /*
        参数说明：
        1. ServerWebExchange exchange:
        这个参数包含了当前HTTP交换的所有信息，
        包括请求(ServerHttpRequest)、响应(ServerHttpResponse)以及可选的属性。
        它是Spring WebFlux框架中的一个核心接口，用于处理HTTP请求和响应。
        2. GatewayFilterChain chain:
        这个参数代表了当前请求的过滤器链。
        它提供了filter(ServerWebExchange)方法，用于将请求传递给链中的下一个过滤器。
        这使得多个过滤器可以按顺序执行，每个过滤器可以做自己的事情，然后将控制权交给下一个过滤器。
         */

        //全局登陆验证
        //1. 判断当前请求是否需要验证：登录相关资源不需要验证，直接放行
        ServerHttpRequest request = exchange.getRequest();
        //这一行代码用于从ServerWebExchange对象中获取当前的HTTP请求对象ServerHttpRequest。
        // request对象封装了所有关于HTTP请求的信息，包括请求方法、URL、请求头、请求体等。
        ServerHttpResponse response = exchange.getResponse();
        //这一行代码用于从ServerWebExchange对象中获取当前的HTTP响应对象ServerHttpResponse。
        // response对象允许你修改或设置HTTP响应的任何部分，如状态码、响应头、响应体等

        //拿到请求路径
        String path = request.getPath().toString();
        log.info("拦截到本次请求路径：{}",path);

        //如果路径包含login，直接放行
        if (path.contains("login")){
            //放行
            return chain.filter(exchange);
        }

        //2. 解析请求头，获取token
        String token = request.getHeaders().getFirst("token");

        //3. 验证token
        //3.1 验证不通过：返回401
        //情况1：压根没给token
        if (StringUtils.isEmpty(token)){
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //情况2：伪造token
        try {
            Claims claimsBody = AppJwtUtil.getClaimsBody(token);
            //-1：有效， 0：有效， 1：过期， 2：过期
            int res = AppJwtUtil.verifyToken(claimsBody);
            if (res != -1 && res != 0){
                response.setStatusCode(HttpStatus.UNAUTHORIZED);
                return response.setComplete();
            }

            //解析出token中的原始数据：当前登录用户id
            Object userId = claimsBody.get("id");

            // 往下游微服务路由时追加请求头：userId = 当前登录用户id
            //在header中添加新的信息
            ServerHttpRequest serverHttpRequest = request.mutate().headers(httpHeaders -> {
                httpHeaders.add("userId", userId + "");
            }).build();

            //重置header
            exchange.mutate().request(serverHttpRequest).build();

        } catch (Exception e) {
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            return response.setComplete();
        }
        //3.2 验证通过：放行
        return chain.filter(exchange);
    }

    @Override
    public int getOrder() {
        return 0;
        //数字越小优先级越高
    }
}
